﻿@using IsaGen
@inherits RazorLight.TemplatePage<IsaExtractor>
@{ DisableEncoding = true;
    string HexTemplate(uint value, uint length)
    {
        var hexForamt = $"X{(int)Math.Ceiling(length / 4f)}";
        return $"0x{value.ToString(hexForamt)}";
    } 

    string SpanReaderMethod(InstructionField field) => field.IsEnum switch {
      true => $"static_cast<{field.CppType}>(reader.read_unaligned<uint{field.Length}_t>())",
      false => field.CppType switch {
        "std::string" =>  $"reader.read_string()",
        "std::vector<std::string>" => $"reader.read_string_array()",
        "gsl::span<const gsl::byte>" => $"reader.read_span(reader.read_unaligned<uint32_t>())",
        _ => $"reader.read_unaligned<{field.CppType}>()",
        },
      };
}
/* This file is generated by tools/stackvm_gen/IsaGen at @Raw(DateTimeOffset.Now.ToString()).
 *
 * Copyright 2019-2021 Canaan Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once
#include "../error.h"
#include "../result.h"
#include "../span_reader.h"
#include "opcode.h"

BEGIN_NS_NNCASE_RT_MODULE(stackvm)

template <opcode_t Op>
struct op_reader;
@foreach (var inst in Model.Instructions.SelectMany(x => x.Value))
{
    var name = inst.CppName.ToLowerInvariant().Replace('.', '_');
@:
@:template <>
@:struct op_reader<opcode_t::@(inst.CppName)>
@:{
@:    @(name)_op_t operator()(NNCASE_UNUSED span_reader &reader) const
@:    {
@:        @(name)_op_t op;
foreach (var field in inst.Fields.Where(x => !x.IsOpCode))
{
@:        op.@field.CppName = @SpanReaderMethod(field);
}
@:        return op;
@:    }
@:};
}

template <tensor_function_t Op>
struct tensor_op_reader;
@foreach (var inst in Model.TensorInstructions.SelectMany(x => x.Value).OrderBy(x => x.CppName))
{
    var name = "tensor_" + inst.CppName.ToLowerInvariant().Replace('.', '_');
@:
@:template <>
@:struct tensor_op_reader<tensor_function_t::@(inst.CppName)>
@:{
@:    @(name)_op_t operator()(NNCASE_UNUSED span_reader &reader) const
@:    {
@:        @(name)_op_t op;
foreach (var field in inst.Fields.Where(x => !x.IsOpCode))
{
@:        op.@field.CppName = @SpanReaderMethod(field);
}
@:        return op;
@:    }
@:};
}

class NNCASE_API tensor_op_visitor
{
public:
    result<void> visit(tensor_function_t tensor_funct, span_reader &reader) noexcept;

    @foreach (var inst in Model.TensorInstructions.SelectMany(x => x.Value).OrderBy(x => x.CppName))
    {
        var name = "tensor_" + inst.CppName.ToLowerInvariant().Replace('.', '_');
@:    virtual result<void> visit(NNCASE_UNUSED const @(name)_op_t &op) noexcept { return default_visit(tensor_function_t::@inst.CppName, &op); }
    }

protected:
    virtual result<void> default_visit(NNCASE_UNUSED tensor_function_t tensor_funct, NNCASE_UNUSED const void *op) noexcept { return err(std::errc::not_supported); }
};

END_NS_NNCASE_RT_MODULE
